Skip to content

Add --import-asm-json input mode. #12704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
Closed

Add --import-asm-json input mode. #12704

wants to merge 10 commits into from

Conversation

aarlt
Copy link
Member

@aarlt aarlt commented Feb 22, 2022

Replaces #11807.
Replaced by #12799,#12809 & #12834.

@aarlt

This comment was marked as resolved.

@aarlt

This comment was marked as resolved.

@aarlt aarlt force-pushed the asm-json-import branch 2 times, most recently from 4128beb to 4b7d64c Compare March 2, 2022 20:25
@aarlt aarlt changed the base branch from develop to update-ci-cmake-jq-buildpacks March 2, 2022 20:38
@aarlt aarlt force-pushed the asm-json-import branch from 4b7d64c to 029751a Compare March 2, 2022 20:40
Base automatically changed from update-ci-cmake-jq-buildpacks to develop March 2, 2022 20:55
@aarlt aarlt force-pushed the asm-json-import branch from 029751a to 4da7da4 Compare March 2, 2022 20:57
@chriseth
Copy link
Contributor

chriseth commented Mar 7, 2022

I assume the question above has been resolved, right?

@aarlt aarlt force-pushed the asm-json-import branch from 4da7da4 to 3981e40 Compare March 7, 2022 22:10
@aarlt aarlt force-pushed the asm-json-import branch from 5b3c7c7 to d464ce1 Compare March 9, 2022 21:55
@aarlt aarlt force-pushed the asm-json-import branch from d464ce1 to c097842 Compare March 14, 2022 14:24
@@ -451,6 +455,13 @@ void CommandLineParser::parseOutputSelection()
CompilerOutputs::componentName(&CompilerOutputs::ewasm),
CompilerOutputs::componentName(&CompilerOutputs::ewasmIR),
};
static set<string> const evmAssemblyJsonImportModeOutputs = {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chriseth @ekpyron does the restriction of the output modes make sense for you too?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cameel can you answer this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, looks sensible. I think they all should be possible to generate from imported assembly.

My only doubt would be about binaryRuntime. If it comes from compiling a contract, we do have the construction/runtime code split. Do we always have it with arbitrary assembly though?

Copy link
Member Author

@aarlt aarlt Mar 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cameel yeah good point. An initial version of this PR did not support any binaryRuntime stuff - because I also saw it like you seem to see it. If I recall correctly, @chriseth wanted to have support for binaryRuntime and also support for the srcmap & srcmap-runtime. I understood it like that it would be great to support as many output modes that are usually also working. To achieve this, of course, we need to have some presumption about the imported assembly json. E.g. structure related to creational code vs. runtime code. Right now not every (well-formed & correct) assembly json will lead be create correct output (e.g. missing "runtime section").

@chriseth @ekpyron This question was more about the high-level view on this PR: if someone uses the asm json import, what should be the supported output-modes. Are my current assumptions to limit and/or support specific output-modes correct?

The main use-case for this I understood like this: someone wrote in contract in solidity, this contract gets exported to asm json, the user may do some tweaks & optimisations on the given code, but e.g. there is no need to change the initial structure e.g. creational code vs runtime code. Of course the user could add more data sections - but the initial structure should not get modified (creational vs runtime). As of now, I also did not really check the behaviour of multiple data sections etc - I guess it should just work, but I'm not entirely sure about this.

The main question is: are my assumptions correct? Do we want to support these output modes for assembly json import? Also for #12704 (comment) - where my assumptions correct to limit and/or support these?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also for #12704 (comment) - where my assumptions correct to limit and/or support these?

This second check is redundant. It's just the opposite of the supported input modes, isn't it?

@@ -941,9 +959,27 @@ void CommandLineParser::processArgs()
for (auto& option: conflictingWithStopAfter)
checkMutuallyExclusive({g_strStopAfter, option});

array<string, 11> const conflictingWithAsmJsonImport{
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chriseth @ekpyron and what about this? does it make sense to not allow those?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again @cameel

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not completely sure about storageLayout. So we lose that info at assembly level?
And --gas - so the estimator must be working at the Solidity level I assume and not by looking at opcodes?

By the way, putting it here seems redundant to me. You already do this check in parseOutputSelection() so this will never fail. conflictingWithStopAfter was here because it's just a regular option, not an input mode. And conflictingWithStopAfter should eventually be integrated into validOptionInputModeCombinations above anyway - this was being refactored in #12166 but it's stalled for now.

@aarlt
Copy link
Member Author

aarlt commented Mar 14, 2022

Regarding the mismatch in the optimised byte-code:

  • Export assembly json
    solc/solc <constract> --asm-json > /tmp/asm.json

  • Equivalence needed for - * I was assuming this *
    solc/solc <contract> —optimize --opcodes (A)
    solc/solc --import-asm-json /tmp/asm.json --opcodes --optimize (B)

Basically for these compilations the used optimiser(-steps) are different. That's why we see a difference in the byte-code. (A) uses class CompilerStack, usingAssemblyStack::optimize(), and that uses OptimiserSuite, where (B) uses Assembly, Assembly::optimise(..), Assembly::optimiseInternal(..). The final optimisation steps differ in both cases.

I think it totally make sense to allow --import-asm-json with --optimize, but not to see it like that we expect that the resulting byte-code of (A) and (B) need to be the same.

@chriseth @ekpyron What do you think?

string const evmSourceName = m_evmAssemblyJson.begin()->first;
Json::Value const evmJson = m_evmAssemblyJson.begin()->second;

evmasm::Assembly::OptimiserSettings optimiserSettings;
Copy link
Member Author

@aarlt aarlt Mar 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I saw somewhere a optimiser-settings transform function.

m_contracts[evmSourceName].evmAssembly = make_shared<evmasm::Assembly>(true, evmSourceName);
m_contracts[evmSourceName].evmAssembly->loadFromAssemblyJSON(m_evmAssemblyJson[evmSourceName]);
if (m_optimiserSettings.enabled)
m_contracts[evmSourceName].evmAssembly->optimise(optimiserSettings);
Copy link
Member Author

@aarlt aarlt Mar 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chriseth @ekpyron I do the optimisation here like this. Does it make sense?

m_contracts[evmSourceName].evmRuntimeAssembly->setSources(m_contracts[evmSourceName].evmAssembly->sources());
m_contracts[evmSourceName].evmRuntimeAssembly->loadFromAssemblyJSON(m_evmAssemblyJson[evmSourceName][".data"]["0"], false);
if (m_optimiserSettings.enabled)
m_contracts[evmSourceName].evmRuntimeAssembly->optimise(optimiserSettings);
Copy link
Member Author

@aarlt aarlt Mar 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chriseth @ekpyron Similar optimisation as above. But for the runtime part. Does it make sense?


m_contracts[evmSourceName].evmRuntimeAssembly = make_shared<evmasm::Assembly>(false, evmSourceName);
m_contracts[evmSourceName].evmRuntimeAssembly->setSources(m_contracts[evmSourceName].evmAssembly->sources());
m_contracts[evmSourceName].evmRuntimeAssembly->loadFromAssemblyJSON(m_evmAssemblyJson[evmSourceName][".data"]["0"], false);
Copy link
Member Author

@aarlt aarlt Mar 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chriseth @ekpyron Does it make sense to load the runtime assembly hardcoded from ".data"[0] here? Not sure whether we should do this dynamically - e.g. that the correct run time will be taken automatically. I guess for this I would need to analyse the "deploy" code. Not sure whether we really want this. What are your opinions?

item.m_modifierDepth = modifierDepth;
if (!value.empty())
item.setJumpType(value);
result = item;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
result = item;
return item;

{
if (!value.empty())
data = u256(value);
updateUsedTags(data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to compute that once at the end from the full list of items?

else if (name == "PUSH [$]")
{
if (!value.empty())
data = u256("0x" + value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check that this works properly when the value starts with a zero (i.e. leading zeros may be removed somewhere in the process).


vector<Json::Value> Assembly::assemblyItemAsJSON(AssemblyItem const& _item, int _sourceIndex) const
{
vector<Json::Value> result;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this return a single Json::Value?

Comment on lines +382 to +384
_item.m_modifierDepth,
_item.location().start,
_item.location().end,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be simplified so that we don't have to pass all three values all the time?

@aarlt
Copy link
Member Author

aarlt commented Mar 15, 2022

After talking to @chriseth, we decided to split-up this PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants